use std::fmt;

use from_pest::FromPest;
use pest::iterators;
use pest_ast::FromPest;
use tracing::debug;
use tracing::trace;

use crate::ast_define::MetaInfo;
use crate::ast_define::Rule;
use crate::ast_define::general::*;
use crate::ast_define::get_meta_info;
use crate::ast_define::keyword::*;
use crate::ast_define::literal::*;
use crate::ast_define::statement::*;

// * 函数类型 FuncType = { VOID | INT }
#[derive(Debug, PartialEq)]
pub enum FuncType {
    VOID(VOID),
    INT(INT),
}

impl fmt::Display for FuncType {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            FuncType::VOID(this) => write!(f, "{this}"),
            FuncType::INT(this) => write!(f, "{this}"),
        }
    }
}

impl<'pest> FromPest<'pest> for FuncType {
    type Rule = Rule;
    type FatalError = from_pest::Void;
    #[tracing::instrument(skip_all)]
    fn from_pest(
        pest: &mut iterators::Pairs<'pest, Rule>,
    ) -> Result<Self, from_pest::ConversionError<from_pest::Void>> {
        trace!("正在解析 FuncType");
        let pair = pest.next().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("pair in FuncType:\n{pair:#?}");
        let Rule::FuncType = pair.as_rule() else {
            trace!("\n{:#?} != Rule::FuncType", pair.as_rule());
            return Err(from_pest::ConversionError::NoMatch);
        };

        let inner = pair.into_inner();
        trace!("inner:\n{inner:#?}");
        let inner_pair = inner.peek().ok_or(from_pest::ConversionError::NoMatch)?;
        trace!("inner_pair:\n{inner_pair:#?}");
        match inner_pair.as_rule() {
            Rule::VOID => Ok(FuncType::VOID(VOID)),
            Rule::INT => Ok(FuncType::INT(INT)),
            _ => Err(from_pest::ConversionError::NoMatch),
        }
    }
}

// * 函数实参表 FuncRParams = { Exp ~ ("," ~ Exp)* }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::FuncRParams))]
pub struct FuncRParams {
    pub exps: Vec<Exp>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for FuncRParams {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let formatted = self.exps.iter().map(|this| this.to_string());
        let formatted = formatted.collect::<Vec<String>>().join(", ");
        write!(f, "{formatted}")?;
        Ok(())
    }
}

// * 函数形参 FuncFParam = { BType ~ Ident ~ ("[" ~ "]" ~ ("[" ~ Exp ~ "]")*)? }

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::BracketsAndExp))]
pub struct BracketsAndExp {
    pub exp_list: Vec<Exp>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for BracketsAndExp {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "[]")?;
        for exp in self.exp_list.iter() {
            write!(f, "[{exp}]")?;
        }
        Ok(())
    }
}

#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::FuncFParam))]
pub struct FuncFParam {
    pub b_type: BType,
    pub ident: Ident,
    pub brackets_and_exp: Option<BracketsAndExp>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for FuncFParam {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{} {}", self.b_type, self.ident)?;
        if let Some(this) = self.brackets_and_exp.as_ref() {
            write!(f, "{this}")?;
        }
        Ok(())
    }
}

// * 函数形参表 FuncFParams = { FuncFParam ~ ("," ~ FuncFParam)* }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::FuncFParams))]
pub struct FuncFParams {
    pub func_f_params: Vec<FuncFParam>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl fmt::Display for FuncFParams {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let formatted = self.func_f_params.iter().map(|this| this.to_string());
        let formatted = formatted.collect::<Vec<String>>().join(", ");
        write!(f, "{formatted}")?;
        Ok(())
    }
}

// * 函数定义 FuncDef = { FuncType ~ Ident ~ "(" ~ FuncFParams? ~ ")" ~ Block }
#[derive(Debug, PartialEq, FromPest)]
#[pest_ast(rule(Rule::FuncDef))]
pub struct FuncDef {
    pub func_type: FuncType,
    pub ident: Ident,
    pub func_f_params: Option<FuncFParams>,
    pub block_items: Vec<BlockItem>,
    #[pest_ast(outer(with(get_meta_info)))]
    pub meta_info: MetaInfo,
}

impl FuncDef {
    /// 带缩进的格式化方法
    pub fn fmt_with_indent(&self, f: &mut fmt::Formatter<'_>, indent: usize) -> fmt::Result {
        write!(f, "{} {}", self.func_type, self.ident)?;
        write!(f, "(")?;
        if let Some(this) = self.func_f_params.as_ref() {
            write!(f, "{this}")?;
        }
        write!(f, ")")?;
        write!(f, " ")?;

        let outer_indent = "    ".repeat(indent);
        let inner_indent = "    ".repeat(indent + 1);
        writeln!(f, "{{")?; // 开大括号后总是换行
        for block_item in &self.block_items {
            write!(f, "{inner_indent}")?;
            block_item.fmt_with_indent(f, indent + 1)?;
            // 不在这里强制换行，让每个语句自己控制换行
        }
        write!(f, "{outer_indent}}}") // 闭大括号前加缩进，不换行（让调用者决定）
    }
}

impl fmt::Display for FuncDef {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        self.fmt_with_indent(f, 0)
    }
}
